{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!--BOOK_INFORMATION-->\n",
    "<img align=\"left\" style=\"padding-right:10px;\" src=\"figures/PHydro-cover-small.png\">\n",
    "*This is the Jupyter notebook version of the [Python in Hydrology](http://www.greenteapress.com/pythonhydro/pythonhydro.html) by Sat Kumar Tomer.*\n",
    "*Source code is available at [code.google.com](https://code.google.com/archive/p/python-in-hydrology/source).*\n",
    "\n",
    "*The book is available under the [GNU Free Documentation License](http://www.gnu.org/copyleft/fdl.html). If you have comments, corrections or suggestions, please send email to satkumartomer@gmail.com.*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<!--NAVIGATION-->\n",
    "< [Data Types](02.01-Data-Types.ipynb) | [Contents](Index.ipynb) | [Choosing the Name of Variable](02.03-Choosing-the-Name-of-Variable.ipynb) >"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.2 数据结构\n",
    "\n",
    "数据结构能够在其中包含多个数据。Python中有四种内嵌的数据结构：列表(list)、元组(tuple)、字典(dictionary)和集合(set)。除了这些内嵌的数据结构，你可以像`numpy.array`一样用`numpy`定义你自己的数据类型，这是非常有用的。我并不觉得有必要在水文学中使用集合，所以我在这里略过集合，如果你有兴趣，你可以从其它渠道学习。\n",
    "\n",
    "## 2.2.1 列表\n",
    "\n",
    "列表是项(值)的序列。其中的项可以属于任何数据类型，并且可以在同一个列表中包含不同的数据类型。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = ['Ram','Sita','Bangalore','Delhi']\n",
    "b = [25, 256, 2656, 0]\n",
    "c = [25,'Bangalore']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "列表中的项使用索引访问。变量a和b容纳类似数据类型的项，而c容纳不同数据类型的项。在Python中，索引从0开始。因此，要得到第一和第三项，索引应该是0和2。 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = ['Ram','Sita','Bangalore','Delhi']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ram\n"
     ]
    }
   ],
   "source": [
    "print(a[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Bangalore\n"
     ]
    }
   ],
   "source": [
    "print(a[2])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python中负数索引也是允许的。列表中最后一项的索引是`-1`,类似地，倒数第二项的索引为`-2`等。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Delhi\n"
     ]
    }
   ],
   "source": [
    "a = ['Ram','Sita','Bangalore','Delhi']\n",
    "print(a[-1])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2.3 字典\n",
    "\n",
    "在列表中，索引只是整数。字典具有将任何数据类型作为索引的能力。当索引名称等时，字典的这一特性使它非常适合。例如，在水文中，每个站点都有字段站点的名称及其相应的变量。让我们先使用列表检索变量的值，然后使用字典。我们可以使用一个列表来存储站点的名称，用另一个列表存储变量的名称。首先，我们需要查找站点的索引，然后使用这些索引从变量列表中访问变量。\n",
    "\n",
    "同样，可以使用索引`-2`访问列表中倒数第二项。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "5\n"
     ]
    }
   ],
   "source": [
    "a = ['Delhi','Bangalore','Kolkata']\n",
    "rainfall = [0, 5, 10]\n",
    "print(rainfall[a.index('Bangalore')])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，让我们使用字典，"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "5"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rainfall = {'Delhi':0,'Bangalore':5,'Kolkata':10}\n",
    "rainfall['Bangalore']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同样的事情也可以在一行中使用，但是字典提供了一个整洁的方法来完成这个任务。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2.3 元组\n",
    "\n",
    "元组是一些列的值，类似于列表，除了元组是不可变(它们的值不能被修改)外。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "18"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "foo = 5,15,18\n",
    "foo[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'tuple' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-11-23e76439239e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mfoo\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "foo[1] = 10"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当尝试修改元组中的项时，Python会出错误。元组在需要指定某些常量，并确保这些变量保持不变时很有用。元组的不可变属性确保在程序执行过程中常量的值不会改变。\n",
    "\n",
    "只有一个项的元组是通过在之后使用`,`来定义的，例如："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "int"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "foo = 5\n",
    "type(foo)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tuple"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "foo = 5,\n",
    "type(foo)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "你可能注意到，如果不使用冒号(,)，Python就不会把它当作元组。\n",
    "\n",
    "### 2.2.4 Numpy.array\n",
    "\n",
    "NumericalPython (NumPy)是一个主要用C语言写的库/包，但为Python提供了应用程序接口(API)。该库提供的`numpy.array`数据类型在数组的数值计算中非常有用，这是我们大多数时候最常处理的数据类型。该库并非标准的Python发行版的一部分，因此在使用前，必须先在系统中安装Numpy。我们可以通过下面的命令来检查Numpy是否已安装在我们的系统中。\n",
    "```\n",
    "$ python -c'import numpy'\n",
    "```\n",
    "如果这个指令没有输出(没有错误)，则表明Numpy已被安装了。如果在系统中Numpy没有被安装，你会看到如下消息(错误)：\n",
    "\n",
    "```\n",
    "$ python -c'import numpy'\n",
    "Traceback (most recent call last):\n",
    "File \"<string>\", line 1, in <module>\n",
    "ImportError: No module named numpy\n",
    "```\n",
    "\n",
    "这意味着，在系统中numpy没有被安装。你可以按照1.3节提供的步骤进行安装。`python -c'import numpy' `是一种运行一些简单代码而不调用Python的方法，当你想要做一些小事时，这是非常有用。当你想要检查某些包是否在系统中已被安装也是非常有用的。\n",
    "\n",
    "在使用任何库之前，应该将其导入到程序中。`import`可以用来导入库。有三种方法从库中导入完整的库或一些函数。通过如下方式导入完整的库："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "list"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy\n",
    "x = [1,2,5,9.0,15] #列表只包含数字(浮点数或整数)\n",
    "type(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "numpy.ndarray"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = numpy.array(x) #将列表转换为numpy数组\n",
    "type(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们将完整的`numpy`库导入后，每当我们需要使用该库中的任何函数(例如`array`)时，只需要提供mi函数名和对应的库名即可(例如，`numpy.array`)。数据函数将整数或/和浮点数列表转化为numpy数组。通常程序库名相当长，可以通过以下方式缩写："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "numpy.ndarray"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "x = np.array(x) #将列表转化为numpy数组\n",
    "type(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果只需要使用很少的功能，那么可以通过明确定义它们的名称来导入它们："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "numpy.ndarray"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from numpy import array\n",
    "x = array(x) #将列表转化为numpy数组\n",
    "type(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "如果需要使用所有的函数，并且不想在它们之前使用`numpy`或`np`，那么可以按照以下方式导入："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "numpy.ndarray"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from numpy import *\n",
    "x = array(x) #将列表转化为numpy数组\n",
    "type(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`#`之后写的任何东西都是对程序的注释，Python不会执行它们。注释对于提高代码的可读性非常有用。注释也可以占用一整行。一个numpy数组是一个齐次的多维数组。它只能够容纳整数、浮点数、整数和浮点数的组合、复数和字符串。如果在`numpy.ndarray`中指定了整数和浮点数的组合，那么将整数视为浮点数。`numpy.ndarray`的数据类型可以使用其属性`dtype`进行检查："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('float64')"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "x = np.array([1,5,9.0,15]) #可直接定义np.array\n",
    "x.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('int32')"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array([1,5,9,15]) #该数组只容纳整型\n",
    "x.dtype"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "dtype('<U5')"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x = np.array(['Delhi','Paris']) #该数组只容纳字符串\n",
    "x.dtype"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数组的平均值可以使用`mean`方法来计算，方法如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "7.5"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "x = np.array([1,5,9.0,15])\n",
    "x.mean()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "你注意到调用属性和方法的区别吗？这些方法对对象执行一些操作,通常操作需要一些输入，所以方法用`()`调用。若需要将一些输入传入给方法，则可以在括号内给出。如果没有输入，则直接使用空括号。尝试使用方法(例如,sum)而不提供括号，你将只会看到关于该方法的细节，而没有输出。\n",
    "\n",
    "由于Python是面向对象编程(OOP)语言，所以属性和方法的使用相当普遍。在直接进入Python之前，最好先对它们有个简要的了解。`Attributes`代表了对象的属性，可以是任何类型，即便是对象的类型也包含它。`methods`代表了对象能做什么。一个属性只能有一个值或一个状态，而一个方法则可以做某些事情或执行一个操作。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
